還記得我們在 Day3-Day4 時介紹了一個狀態管理套件,今天我們就要把他套在我們的代辦清單啦~
首先我們先在 lib/providers/todos.dart
建立一個新的目錄與檔案:
import "package:flutter/foundation.dart";
class Todo with ChangeNotifier {
final int id;
final String title;
final String description;
bool done;
Todo({this.id, this.title, this.description, this.done});
void toggleDone() {
done = !done;
notifyListeners();
}
}
class Todos with ChangeNotifier {
List<Todo> _items = [
Todo(id: 1, title: "Test1", description: "abc123", done: false),
Todo(id: 2, title: "Test2", description: "abc123", done: false),
Todo(id: 3, title: "Test3", description: "abc123", done: false),
Todo(id: 4, title: "Test4", description: "abc123", done: true),
Todo(id: 5, title: "Test5", description: "abc123", done: false),
Todo(id: 6, title: "Test6", description: "abc123", done: true),
Todo(id: 7, title: "Test7", description: "abc123", done: false),
Todo(id: 8, title: "Test8", description: "abc123", done: false),
];
List<Todo> get items {
return [..._items];
}
void addTodo(Todo todo) {
final newTodo = Todo(
title: todo.title,
description: todo.description,
done: false,
);
// _items.add(newTodo);
_items.insert(0, newTodo); // at the start of list
notifyListeners();
}
void deleteTodo(int itemId) {
final existingTodoIndex = _items.indexWhere((prod) => prod.id == itemId);
// var existingTodo = _items[existingTodoIndex];
_items.removeAt(existingTodoIndex);
notifyListeners();
}
}
把所有的狀態都搬到這裡,且會改變狀態的函式也全數搬過來,調整了一番邏輯之後就大功告成拉~
記得在改變狀態後需要加上 notifyListeners()
,讓使用這些狀態的組件可以監聽到變化哦~
接下來使用我們的Provider Widget把我們的 App 包起來:
import 'package:flutter/material.dart';
import './screens/todos_homepage.dart';
import 'package:provider/provider.dart';
import './providers/todos.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
builder: (_) => Todos(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TodosHomepage(),
),
);
}
}
這樣子目錄就可以隨時使用Todos的方法,或狀態囉~
以下看看我們要怎麼在TodosHomepage
取得Todos的狀態吧!
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:provider/provider.dart';
import '../widgets/todo_tile.dart';
import '../screens/edit_todo_screen.dart';
import '../providers/todos.dart';
class TodosHomepage extends StatefulWidget {
@override
_TodosHomepageState createState() => _TodosHomepageState();
}
class _TodosHomepageState extends State<TodosHomepage> {
final SlidableController slidableController = SlidableController();
@override
Widget build(BuildContext context) {
final todosProvider = Provider.of<Todos>(context);
return Scaffold(
appBar: AppBar(
title: Text('Todos'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (ctx) => EditTodoScreen(),
),
);
},
)
],
),
body: ListView.builder(
itemCount: todosProvider.items.length,
itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
value: todosProvider.items[i],
child: TodoTile(slidableController: slidableController),
),
),
);
}
}
我們可以使用 final todosProvider = Provider.of<Todos>(context);
這樣我們只需要,todosProvider.items 我們就可以拿到所有待辦清單的List。
然後我這邊又包了一個 ChangeNotifierProvider.value
把我們的一個一個的待辦清單分開丟到TodoTile
這樣我們就可以不用一個一個參數往裡面傳,且當done被更新我們也可以監聽的到,即時的改變渲染,是不是很棒啊!
最後的最後我們來看看我們的 lib/widgets/todo_tile.dart
我再想想看要怎麼解釋,今天就先這樣拉~
一樣附上我的原始碼:
https://github.com/kevinypfan/ithome-todo-project